package cn.wizzer.app.crown.commons.websocket;

import cn.wizzer.app.crown.commons.util.DecipherUtil;
import cn.wizzer.app.crown.modules.models.constant.CrownRedisConstant;
import cn.wizzer.app.crown.modules.models.vo.CrownXML;
import cn.wizzer.app.crown.modules.services.impl.pl.PdHalfResolverServiceImpl;
import cn.wizzer.app.crown.modules.services.impl.pl.PdNewestServiceImpl;
import cn.wizzer.app.crown.modules.services.impl.pl.PdResolverServiceImpl;
import cn.wizzer.app.crown.modules.services.impl.pl.TResolverServiceImpl;
import cn.wizzer.app.crown.modules.services.impl.result.MatchResultServiceImpl;
import cn.wizzer.app.sys.modules.models.SysParam;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.framework.util.JSONUtil;
import cn.wizzer.framework.util.ThreadUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

@IocBean(depose = "close")
public class CrawlerWebSocketClient extends WebSocketClient {

    private static final Log log = Logs.get();

    private static CrawlerWebSocketClient client;

    public static CrawlerWebSocketClient instance() {
        return client;
    }

    public CrawlerWebSocketClient(String url) throws URISyntaxException {
        super(new URI(url));
        client = this;
    }

    @Inject
    public PdHalfResolverServiceImpl pdHalfResolverService;
    @Inject
    public PdResolverServiceImpl pdResolverService;
    @Inject
    public TResolverServiceImpl tResolverService;
    @Inject
    public MatchResultServiceImpl matchResultService;
    @Inject
    public PdNewestServiceImpl pdNewestService;
    @Inject
    public Ioc ioc;
    @Inject
    public RedisService redisService;

    private void subscribe() {
        SysParam sysParam = pdHalfResolverService.getSysParamService().fetch();
        //订阅 pd
        this.send("/crown/match/pd?no=" + sysParam.getCrawlerNo() + "&data=" + DecipherUtil.encrypt(sysParam.getCrawlerSecret(), "subscribe=pagination"));
        //订阅 pdf
        this.send("/crown/match/fpd?no=" + sysParam.getCrawlerNo() + "&data=" + DecipherUtil.encrypt(sysParam.getCrawlerSecret(), "subscribe=pagination"));
        //订阅 tr
        this.send("/crown/match/t?no=" + sysParam.getCrawlerNo() + "&data=" + DecipherUtil.encrypt(sysParam.getCrawlerSecret(), "subscribe=pagination"));
        //订阅 result
        this.send("/crown/match/result?no=" + sysParam.getCrawlerNo() + "&data=" + DecipherUtil.encrypt(sysParam.getCrawlerSecret(), "subscribe=detail"));
        //订阅新版皇冠 pd
        this.send("/crown/match/newestPd?no=" + sysParam.getCrawlerNo() + "&data=" + DecipherUtil.encrypt(sysParam.getCrawlerSecret(), "subscribe=xml"));

    }

    @Override
    public void onOpen(ServerHandshake shake) {
        //建立连接后订阅消息
        subscribe();
    }

    @Override
    public void onMessage(String paramString) {
        ThreadUtil.execute(() -> {
            log.info("onMessage:"+paramString);
            // 回调处理
            JSONObject resp = JSONUtil.parseToJSON(paramString);
            //订阅响应不予处理
            if (resp.getInteger("code") != null) {
                return;
            }
            String key = resp.getString("key");
            JSONObject data = resp.getJSONObject("data");
            Integer code = data.getInteger("code");
            data = data.getJSONObject("data");
            if (code.equals(-3)) {
                long exTime = data.getLong("data");
                redisService.set(CrownRedisConstant.CROWN_MAINTAIN, CrownRedisConstant.CROWN_MAINTAIN, "NX", "EX", exTime);
            } else if (code.equals(0)) {
                log.info(key + "-接收通知");
                if (key.contains("/crown/match/pd")) {
                    JSONArray array = data.getJSONArray("list");
                    List<JSONArray> list = new ArrayList<>(array.size());
                    for (int i = 0; i < array.size(); i++) {
                        list.add(array.getJSONArray(i));
                    }
                    pdResolverService.doBiz(list, data.getString("date"), data.getString("dateType"));
                } else if (key.contains("/crown/match/fpd")) {
                    JSONArray array = data.getJSONArray("list");
                    List<JSONArray> list = new ArrayList<>(array.size());
                    for (int i = 0; i < array.size(); i++) {
                        list.add(array.getJSONArray(i));
                    }
                    pdHalfResolverService.doBiz(list, data.getString("date"), data.getString("dateType"));
                } else if (key.contains("/crown/match/t")) {
                    JSONArray array = data.getJSONArray("list");
                    List<JSONArray> list = new ArrayList<>(array.size());
                    for (int i = 0; i < array.size(); i++) {
                        list.add(array.getJSONArray(i));
                    }
                    tResolverService.doBiz(list, data.getString("date"), data.getString("dateType"));
                } else if (key.contains("/crown/match/result")) {
                    JSONArray array = data.getJSONArray("list");
                    matchResultService.goalsNum(array, data.getString("mid"));
                }
                // 增加新版皇冠的接收
                else if (key.contains("/crown/match/newestPd")) {
                    CrownXML crownxml = data.getObject("CrownXML", CrownXML.class);
                    pdNewestService.handleReceiveData(crownxml, data.getString("dateType"));
                }
            }
        });
    }

    @Override
    public void onClose(int paramInt, String paramString, boolean paramBoolean) {
        //todo 通知管理员检查
        this.close(1);
        log.error("websocket connect failed");
        long start = System.currentTimeMillis();
        long times = System.currentTimeMillis() - start;
        if (times < 1000L) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                log.error("Thread sleep异常:" + ex.getMessage());
            }
        }
        init(pdHalfResolverService.getSysParamService(), ioc);
    }

    @Override
    public void onError(Exception e) {
        //关闭新建
        this.close(1);
        log.error("websocket has some error:" + e);

    }

    public void waitForConnected() {
        boolean flag = true;
        while (flag) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (this.getReadyState().equals(WebSocket.READYSTATE.OPEN) || this.getReadyState().equals(READYSTATE.CLOSED)) {
                flag = false;
            }
        }
    }

    public static void init(SysParamService sysParamService, Ioc ioc) {
        CrawlerWebSocketClient client = null;
        try {
            client = new CrawlerWebSocketClient(sysParamService.fetch().getCrawlerAddress());
            ioc.addBean("crawlerWebSocketClient", client);
            for (Field field : CrawlerWebSocketClient.class.getDeclaredFields()) {
                Inject inject = field.getAnnotation(Inject.class);
                if (inject != null) {
                    try {
                        if (field.getType().equals(Ioc.class)) {
                            field.set(client, ioc);
                        } else {
                            field.set(client, ioc.get(field.getType()));
                        }
                    } catch (Exception e) {
                        log.info(e);
                    }
                }
            }


            client.connect();
        } catch (Exception e) {
            log.error(e);
        }
    }
}